﻿using gt.rediscachemanager.Entry;
using gt.rediscachemanager.Utility;
using StackExchange.Redis;
using System;
using System.Threading.Tasks;

namespace gt.rediscachemanager.Impl.RedisClient
{
    public partial class RedisClient
    {
        public bool SetAdd(string key, string value, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new SetAddMessage(key, value);
            return Execute(RedisCommand.SetAdd, message, flags).BoolResult;
        }

        public long SetAdd(string key, string[] values, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            RedisValue[] value = RedisValueUtility.Convert(values);
            var message = new SetAddArrayMessage(key, value);
            return Execute(RedisCommand.SetAddArray, message, flags).LongResult;
        }

        public string[] SetCombine(StackExchange.Redis.SetOperation operation, string[] keys, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            if (this.Pool.Mode != PoolMode.Single) throw new InvalidOperationException("this operation do not support by cluster mode!");
            RedisKey[] value = RedisValueUtility.ConvertToRedisKeyFromString(keys);
            var message = new SetCombineArrayMessage(operation, value);
            var result = Execute(RedisCommand.SetCombineArray, message, flags).RedisValueArrayResult;
            return RedisValueUtility.Convert(result);
        }

        public string[] SetCombine(SetOperation operation, string first, string second, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            if (this.Pool.Mode != PoolMode.Single) throw new InvalidOperationException("this operation do not support by cluster mode!");
            var message = new SetCombineMessage(operation, first, second);
            var result = Execute(RedisCommand.SetCombine, message, flags).RedisValueArrayResult;
            return RedisValueUtility.Convert(result);
        }

        public long SetCombineAndStore(StackExchange.Redis.SetOperation operation, string destination, string[] keys, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            if (this.Pool.Mode != PoolMode.Single) throw new InvalidOperationException("this operation do not support by cluster mode!");
            RedisKey[] value = RedisValueUtility.ConvertToRedisKeyFromString(keys);
            var message = new SetCombineAndStoreArrayMessage(operation, destination, value);
            return Execute(RedisCommand.SetCombineAndStoreArray, message, flags).LongResult;
        }

        public long SetCombineAndStore(StackExchange.Redis.SetOperation operation, string destination, string first, string second, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            if (this.Pool.Mode != PoolMode.Single) throw new InvalidOperationException("this operation do not support by cluster mode!");
            var message = new SetCombineAndStoreMessage(operation, destination, first, second);
            return Execute(RedisCommand.SetCombineAndStore, message, flags).LongResult;
        }

        public bool SetContains(string key, string value, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new SetContainsMessage(key, value);
            return Execute(RedisCommand.SetContains, message, flags).BoolResult;
        }

        public long SetLength(string key, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new SetLengthMessage(key);
            return Execute(RedisCommand.SetLength, message, flags).LongResult;
        }

        public string[] SetMembers(string key, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new SeMembersMessage(key);
            var result = Execute(RedisCommand.SetMembers, message, flags).RedisValueArrayResult;
            return RedisValueUtility.Convert(result);
        }

        public bool SetMove(string source, string destination, string value, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            if (this.Pool.Mode != PoolMode.Single) throw new InvalidOperationException("this operation do not support by cluster mode!");
            var message = new SetMoveMessage(source, destination, value);
            return Execute(RedisCommand.SetMove, message, flags).BoolResult;
        }

        public string SetPop(string key, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new SetPopMessage(key);
            return Execute(RedisCommand.SetPop, message, flags).RedisValueResult;
        }

        public string SetRandomMember(string key, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new SetRandomMemeberMessage(key);
            return Execute(RedisCommand.SetRandomMember, message, flags).RedisValueResult;
        }

        public string[] SetRandomMembers(string key, long count, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new SetRandomMembersMessage(key, count);
            var result = Execute(RedisCommand.SetRandomMembers, message, flags).RedisValueArrayResult;
            return RedisValueUtility.Convert(result);
        }

        public long SetRemove(string key, string[] values, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            if (this.Pool.Mode != PoolMode.Single) throw new InvalidOperationException("this operation do not support by cluster mode!");
            var value = RedisValueUtility.Convert(values);
            var message = new SetRemoveArrayMessage(key, value);
            return Execute(RedisCommand.SetRemoveArray, message, flags).LongResult;
        }

        public bool SetRemove(string key, string value, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new SetRemoveMessage(key, value);
            return Execute(RedisCommand.SetRemove, message, flags).BoolResult;
        }

        #region async

        public async Task<bool> SetAddAsync(string key, string value, CommandFlags flags = CommandFlags.None)
        {
            var message = new SetAddMessage(key, value);
            return await ExecuteAsync(RedisCommand.SetAdd, message, flags).ContinueWith(t =>
            {
                return t.Result.BoolResult;
            }).ConfigureAwait(false);
        }

        public async Task<long> SetAddAsync(string key, string[] values, CommandFlags flags = CommandFlags.None)
        {
            RedisValue[] value = RedisValueUtility.Convert(values);
            var message = new SetAddArrayMessage(key, value);
            return await ExecuteAsync(RedisCommand.SetAddArray, message, flags).ContinueWith(t =>
            {
                return t.Result.LongResult;
            }).ConfigureAwait(false);
        }

        public async Task<string[]> SetCombineAsync(SetOperation operation, string[] keys, CommandFlags flags = CommandFlags.None)
        {
            if (this.Pool.Mode != PoolMode.Single) throw new InvalidOperationException("this operation do not support by cluster mode!");
            RedisKey[] value = RedisValueUtility.ConvertToRedisKeyFromString(keys);
            var message = new SetCombineArrayMessage(operation, value);
            return await ExecuteAsync(RedisCommand.SetCombineArray, message, flags).ContinueWith((task) =>
            {
                return RedisValueUtility.Convert(task.Result.RedisValueArrayResult);
            }).ConfigureAwait(false);
        }

        public async Task<string[]> SetCombineAsync(SetOperation operation, string first, string second, CommandFlags flags = CommandFlags.None)
        {
            if (this.Pool.Mode != PoolMode.Single) throw new InvalidOperationException("this operation do not support by cluster mode!");
            var message = new SetCombineMessage(operation, first, second);
            return await ExecuteAsync(RedisCommand.SetCombine, message, flags).ContinueWith((task) =>
            {
                return RedisValueUtility.Convert(task.Result.RedisValueArrayResult);
            }).ConfigureAwait(false);

        }

        public async Task<long> SetCombineAndStoreAsync(SetOperation operation, string destination, string[] keys, CommandFlags flags = CommandFlags.None)
        {
            if (this.Pool.Mode != PoolMode.Single) throw new InvalidOperationException("this operation do not support by cluster mode!");
            RedisKey[] value = RedisValueUtility.ConvertToRedisKeyFromString(keys);
            var message = new SetCombineAndStoreArrayMessage(operation, destination, value);
            return await ExecuteAsync(RedisCommand.SetCombineAndStoreArray, message, flags).ContinueWith(t =>
            {
                return t.Result.LongResult;
            }).ConfigureAwait(false);
        }

        public async Task<long> SetCombineAndStoreAsync(SetOperation operation, string destination, string first, string second, CommandFlags flags = CommandFlags.None)
        {
            if (this.Pool.Mode != PoolMode.Single) throw new InvalidOperationException("this operation do not support by cluster mode!");
            var message = new SetCombineAndStoreMessage(operation, destination, first, second);
            return await ExecuteAsync(RedisCommand.SetCombineAndStore, message, flags).ContinueWith(t =>
            {
                return t.Result.LongResult;
            }).ConfigureAwait(false);
        }

        public async Task<bool> SetContainsAsync(string key, string value, CommandFlags flags = CommandFlags.None)
        {
            var message = new SetContainsMessage(key, value);
            return await ExecuteAsync(RedisCommand.SetContains, message, flags).ContinueWith(t =>
            {
                return t.Result.BoolResult;
            }).ConfigureAwait(false);
        }

        public async Task<long> SetLengthAsync(string key, CommandFlags flags = CommandFlags.None)
        {
            var message = new SetLengthMessage(key);
            return await ExecuteAsync(RedisCommand.SetLength, message, flags).ContinueWith(t =>
            {
                return t.Result.LongResult;
            }).ConfigureAwait(false);
        }

        public async Task<string[]> SetMembersAsync(string key, CommandFlags flags = CommandFlags.None)
        {
            var message = new SeMembersMessage(key);
            return await ExecuteAsync(RedisCommand.SetMembers, message, flags).ContinueWith((task) =>
            {
                return RedisValueUtility.Convert(task.Result.RedisValueArrayResult);
            }).ConfigureAwait(false);
        }

        public async Task<bool> SetMoveAsync(string source, string destination, string value, CommandFlags flags = CommandFlags.None)
        {
            if (this.Pool.Mode != PoolMode.Single) throw new InvalidOperationException("this operation do not support by cluster mode!");
            var message = new SetMoveMessage(source, destination, value);
            return await ExecuteAsync(RedisCommand.SetMove, message, flags).ContinueWith(t =>
            {
                return t.Result.BoolResult;
            }).ConfigureAwait(false);
        }

        public async Task<string> SetPopAsync(string key, CommandFlags flags = CommandFlags.None)
        {
            var message = new SetPopMessage(key);
            return await ExecuteAsync(RedisCommand.SetPop, message, flags).ContinueWith(t =>
            {
                return t.Result.RedisValueResult;
            }).ConfigureAwait(false);
        }

        public async Task<string> SetRandomMemberAsync(string key, CommandFlags flags = CommandFlags.None)
        {
            var message = new SetRandomMemeberMessage(key);
            return await ExecuteAsync(RedisCommand.SetRandomMember, message, flags).ContinueWith(t =>
            {
                return t.Result.RedisValueResult;
            }).ConfigureAwait(false);
        }

        public async Task<string[]> SetRandomMembersAsync(string key, long count, CommandFlags flags = CommandFlags.None)
        {
            var message = new SetRandomMembersMessage(key, count);
            return await ExecuteAsync(RedisCommand.SetRandomMembers, message, flags).ContinueWith((task) =>
            {
                return RedisValueUtility.Convert(task.Result.RedisValueArrayResult);
            }).ConfigureAwait(false);
        }

        public async Task<long> SetRemoveAsync(string key, string[] values, CommandFlags flags = CommandFlags.None)
        {
            if (this.Pool.Mode != PoolMode.Single) throw new InvalidOperationException("this operation do not support by cluster mode!");
            var value = RedisValueUtility.Convert(values);
            var message = new SetRemoveArrayMessage(key, value);
            return await ExecuteAsync(RedisCommand.SetRemoveArray, message, flags).ContinueWith(t =>
            {
                return t.Result.LongResult;
            }).ConfigureAwait(false);
        }

        public async Task<bool> SetRemoveAsync(string key, string value, CommandFlags flags = CommandFlags.None)
        {
            var message = new SetRemoveMessage(key, value);
            return await ExecuteAsync(RedisCommand.SetRemove, message, flags).ContinueWith(t =>
            {
                return t.Result.BoolResult;
            }).ConfigureAwait(false);
        }

        #endregion
    }
}
